#define _CRT_SECURE_NO_WARNINGS
#include"Slist.h"
SListNode* BuySListNode(SLTDateType x)
//为了实现链式访问，还是需要返回值的，向堆区开辟空间，要考虑大小，
//
{
	SListNode* newnode=(SListNode*)malloc(sizeof(SListNode));

	if (newnode == NULL)
	{
		perror("malloc failed");
		exit(-1);
	}

	newnode->Data = x;//开辟完毕
	newnode->next = NULL;

	return newnode;
}

void SListPrint(SListNode* phead)
{
	assert(phead);

	SListNode* cur = phead;

	while (cur != NULL)
	{
		printf("%d->", cur->Data);
		cur = cur->next;
	}

	printf("NULL\n");//实现完链式访问后打印结束的标志
}


void SListPushBack(SListNode** pplist, SLTDateType x)
// 单链表尾插

{
	assert(pplist);
	SListNode* newnode = BuySListNode(x);


	if (*pplist == NULL)//当链表头子是空的时候，我们把创建好的节点的地址付给头子的指针域，让它的指针域可以指向
						//我们新建的节点。
	{
		*pplist = newnode;
	}
	else
		//当链表头子不是空的时候，我们要寻找尾部去插入，如何寻找尾部呢？我们新拟定一个结构体指针，让它从链表头子开始向后
		//寻链，一条条的寻找下去直到它自己本身的next是NULL的时候，这个时候就成功的找到了尾部，找到之后，将新节点的值
		//赋值给尾部指针的next就可以实现尾插了。
	{
		SListNode* end = *pplist;
		while (end->next != NULL)
		{
			end = end->next;
		}
		end->next = newnode;
	}
}

void SListPushFront(SListNode** pplist, SLTDateType x)
//单链表头插的逻辑是，我将新开辟的的节点里面指向下一个节点的指针域的值指向phead，也就是所有节点的
//头头，在赋值完毕之后，将当前的phead指向这个头插的节点变成新的phead以实现头插
//为什么要用二级指针？
//因为在这里，我们希望改变的是这个指针所指向的东西产生变化，但如果只是一级指针，改变的只是传进去的形参，看上去是被改变了
//但其实改变的只是形参，完全没有改到函数外面的那个地址，因为对于*plist来说就和传递交换函数只传递intx一样，我
//只能改变它的形参，根本改不到它的实参，那么，我们为了能真切的改变到这个指针变量的地址，就需要二级指针，二级指针就是
//存放指针变量的指针变量，这个时候传进去改变的地址才可以真真切切的改变到一级指针所指向的地址。
//总结一下：也就是当我们希望使用函数来改变一个实参的值的时候，一定要上升一个层级，也就是想尽办法去得到它的地址之后解引用
//之后去更改其实参
{
	assert(pplist);

	SListNode* newnode=  BuySListNode(x);

	newnode->next = *pplist;
	*pplist = newnode;

}

void SListPopBack(SListNode** pplist)
//尾部删除，涉及到两种情况和尾插是一样的，当整个链表只剩下一个链表头子的时候销毁链表头子，也就是链表头子-》next==NULL的时候
//接下来的情况就是获取尾部的节点然后free掉data开辟的空间，将指针域置空即可，在最开始的时候还是要检测以下
//plist是否为空，为空的话非常危险，所以在最开始的时候需要注意以下这个情况。
//但是！尾部指针消除完了，它上一个的next也是要置空的！那么就诞生了两种解决方法：1.使用两个指针，前一个指针动完了第二个指针
//移动，2.我直接找倒数第二个指针，也就是访问edn->next->next，当这个next里是null的时候置空。
{

	assert(pplist);
	if (*pplist == NULL)
	{
		return;
	}


	if ((*pplist)->next == NULL)
	{
		free((*pplist));
		(*pplist) = NULL;
	}
	else
	{
		SListNode* end = *pplist;
		SListNode* prev = *pplist;

		while (end->next != NULL)
		{
			prev = end;
			end = end->next;

		}
		free(end);
		prev->next = NULL;
		end = NULL;

	}

}

void SListPopFront(SListNode** pplist)
//链表头删，也就是直接先删除pplist所指向的节点进行置空与释放但是在置空与销毁之前，需要先将把pplist引渡到下个节点里。
//我觉得可以创建一个专门准备销毁当前pplist所在的结构体指针，在pplist指向下一个节点之后销毁当前节点。
{
	assert(pplist);

	if (*pplist == NULL)//为空可以插入，但绝对不能删除
	{
		return;
	}

	
	SListNode* destory = *pplist;

	//*pplist = (*pplist)->next;
	*pplist = destory->next;
	free(destory);
	destory = NULL;

}

// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x)
//只是访问数据的时候不需要改变其地址了，就不需要二级指针了
{
	assert(plist);
	
	SListNode* cur = plist;

	while (cur)
	{
		if (cur->Data == x)
		{
			return cur;
		}
		cur = cur->next;
	}

	return NULL;

}
void SListInsertBefore(SListNode** pplist ,SListNode* pos, SLTDateType x)
//在POS之前插入。
{
	assert(pplist);
	assert(pos);

	SListNode* cur = *pplist;

	if ((*pplist)->next == NULL)
	{
		SListPushFront(*pplist, x);
	}

	else
	{
		while (cur->next != pos)
		{
			cur = cur->next;
			assert(cur);
		}
		SListNode* newnode = BuySListNode(x);

		cur->next = newnode;

		newnode->next = pos;
	}

}


// 单链表在pos位置之后插入x
// 分析思考为什么不在pos位置之前插入？因为很难让前面那一个节点的下一个指针域指向自己，也就是难以找到上一个节点
void SListInsertAfter(SListNode* pos, SLTDateType x)
{

	assert(pos);

	SListNode* newnode = BuySListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;


}


void SListDestroy(SListNode** pplist)
{
	assert(pplist);

	SListNode* cur = *pplist;
	SListNode* nextcur;

	while (cur)
	{
		nextcur = cur->next;
		free(cur);
		cur = nextcur;
	}

	*pplist = NULL;
}
//maRKE UP
\